﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using DefCore.Core;
using DefCore.Tools;
using Ivory;
using Krypton.Lights;
using Krypton;
using DefCore.Interfaces;
using DefCore.Cameras;
using DefCore.Structures;
using FarseerPhysics.Dynamics;
using FarseerPhysics.Factories;
using FarseerPhysics.SamplesFramework;

namespace DefCore.Mapping
{
    public abstract class CellBase : IViewable, ISelectable
    {
        //Fields 
        private StructualFrame StructureFrame { get; set; }
        public Texture2D WallTexture { get; private set; }
        public DungeonPos MapPosition { get; private set; }

        public virtual ShadowHull CellShadowHull
        {
            get
            {
                Vector2 size = new Vector2(Globals.TileSize.X, Globals.TileSize.Y);
                var result = ShadowHull.CreateRectangle(size);
                result.Position = MapPosition.ScreenSpaceCoords + (size / 2);
                return result;
            }
        }
        public virtual Light2D CellLight
        {
            get { return null; }
        }

        public Body CellBody
        {
            get;
            private set;
        }
        public Rectangle HitBox
        {
            get
            {
                if (CellBody == null)
                    return new Rectangle(
                        (int)(MapPosition.WorldPosition.X - Objects.GameCamera.CameraTopLeft.X),
                        (int)(MapPosition.WorldPosition.Y - Objects.GameCamera.CameraTopLeft.Y),
                        (int)Globals.TileSize.X, (int)Globals.TileSize.Y);
                else
                {

                    Rectangle r = new Rectangle(
                        (int)(ConvertUnits.ToDisplayUnits(CellBody.Position.X) - (Globals.TileSize.X / 2f)),
                        (int)(ConvertUnits.ToDisplayUnits(CellBody.Position.Y) - (Globals.TileSize.Y / 2f)),
                        (int)Globals.TileSize.X, (int)Globals.TileSize.Y);

                    r.X -= (int)(Objects.GameCamera.CameraTopLeft.X);
                    r.Y -= (int)(Objects.GameCamera.CameraTopLeft.Y);
                    return r;
                }
            }
        }

        public virtual CellFrameType ValidFrameTypes { get { return CellFrameType.SEMIFRAME | CellFrameType.FULLFRAME; } }
        public abstract bool IsBuildable { get; }
        public abstract bool IsWalkable { get; }
        
        public int HitIndex
        {
            get { return 0; }
        }
        public bool IsSelected
        {
            get;
            set;
        }
        public bool IsHoverTarget
        {
            get;
            set;
        }
        public virtual bool IsSelectable
        {
            get;
            protected set;
        }
                     
        public bool NorthNeighboughOpen { get; set; }
        public bool SouthNeighboughOpen { get; set; }
        public bool EastNeighboughOpen { get; set; }
        public bool WestNeighboughOpen { get; set; }

        //cTor
        public CellBase(DungeonPos pos, bool createBody = true)
        {
            this.MapPosition = pos;    
            this.StructureFrame = new StructualFrame(this);
            if (createBody)
                CreateBody();
        }

        //Methods
        private void CreateBody()
        {
            this.CellBody = BodyFactory.CreateRectangle(Objects.GameWorld,
                ConvertUnits.ToSimUnits(Globals.TileSize.X),
                ConvertUnits.ToSimUnits(Globals.TileSize.Y),
                1f, LOSCollisionCategory.Wall);


            this.CellBody.Position = new Vector2(
                ConvertUnits.ToSimUnits(MapPosition.CenterTile.X),
                ConvertUnits.ToSimUnits(MapPosition.CenterTile.Y));

            this.CellBody.BodyType = BodyType.Static;
            this.CellBody.Restitution = 0f;
        }
        protected void SafeDeleteBody()
        {
            if (CellBody != null)
            {
                Objects.GameWorld.RemoveBody(this.CellBody);
                this.CellBody = null;
            }
        }
        
        protected abstract void DrawCell(SpriteBatch batch, Rectangle drawingRect);
        protected abstract void SolveCell(InputControl control, GameTime time);
        
        protected virtual bool LoadCell() { return true; }

        public void Render(SpriteBatch batch, GameTime time)
        {
            Rectangle drawingRect = new Rectangle(0, 0, 0, 0);

            drawingRect.X = (int)((Globals.TileSize.X * MapPosition.MapX) - Objects.GameCamera.CameraTopLeft.X);
            drawingRect.Y = (int)((Globals.TileSize.Y * MapPosition.MapY) - Objects.GameCamera.CameraTopLeft.Y);
            drawingRect.Width = (int)(Globals.TileSize.X);
            drawingRect.Height = (int)(Globals.TileSize.Y);

            //drawingRect = Camera.SizeWithZoom(drawingRect);
            DrawCell(batch, drawingRect);

            if (IsBuildable && CellMap.RenderStructureFrames)
                StructureFrame.Render(batch, HitBox, time);
            else if (IsHoverTarget)
                batch.Draw(ResourceBin.Instance.Get<Texture2D>("ASSET_SELECTOR"), HitBox, Color.Red);
        }
        public void Solve(InputControl control, GameTime time)
        {
            SolveCell(control, time);
        }
         
        public bool Load()
        {
            return true;
        }

        public bool PlaceFrame(StructureFrameEnum frame)
        {
            return StructureFrame.PlaceFrame(frame);
        }
        public bool IsOccupied(StructureFrameEnum frame, StructureFrameEnum? with = null)
        {
            return StructureFrame.IsOccuppied(frame, with);
        }

        public StructureFrameEnum GetActiveFrame(InputControl control)
        {
            if (!NorthNeighboughOpen && FrameManager.GetFrame(StructureFrameEnum.NORTHFRAME, this).Contains(control.MousePoint))
                return StructureFrameEnum.NORTHFRAME;

            else if (!EastNeighboughOpen && FrameManager.GetFrame(StructureFrameEnum.EASTFRAME, this).Contains(control.MousePoint))
                return StructureFrameEnum.EASTFRAME;

            else if (!SouthNeighboughOpen && FrameManager.GetFrame(StructureFrameEnum.SOUTHFRAME, this).Contains(control.MousePoint))
                return StructureFrameEnum.SOUTHFRAME;

            else if (!WestNeighboughOpen && FrameManager.GetFrame(StructureFrameEnum.WESTFRAME, this).Contains(control.MousePoint))
                return StructureFrameEnum.WESTFRAME;

            else if (FrameManager.GetFrame(StructureFrameEnum.CENTERFRAME, this).Contains(control.MousePoint))
                return StructureFrameEnum.CENTERFRAME;
            else
                return 0;

            throw new NotImplementedException();
        }

        public void FreeFrame(StructureFrameEnum frame)
        {
            StructureFrame.FreeFrame(frame);
        }
    }
}
